package cn.sc.summer.mybatis.strategy.basestage;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.TypeReference;
import cn.hutool.extra.spring.SpringUtil;
import cn.sc.summer.mybatis.model.*;
import cn.sc.summer.mybatis.table.comparison.ColumnComparison;
import cn.sc.summer.mybatis.table.comparison.TableComparison;
import cn.sc.summer.mybatis.table.datasource.DataSourceTableInfo;
import cn.sc.summer.constant.model.ListChange;
import cn.sc.summer.constant.mybatisplus.datasource.TableColumn;
import cn.sc.summer.constant.mybatisplus.datasource.TableInfo;
import cn.sc.summer.constant.util.ListUtilX;
import cn.sc.summer.mybatis.model.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.jdbc.core.JdbcTemplate;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 类名：比对接口，用于获取表结构的新增，更新或者删除
 *
 * @author a-xin
 * @date 2024/8/28 17:09
 */
@Slf4j
public abstract class Comparison implements TableComparison, ColumnComparison {

    private static final long serialVersionUID = -8777923763834877509L;

    /**
     * java代码实体类映射表信息
     */
    public static final List<TableXInfo> TABLE_X_INFOS = new ArrayList<>();

    /**
     * 数据源表信息
     */
    public static final List<TableInfo> TABLE_INFOS = new ArrayList<>();

    /**
     * 获取所有主键信息
     *
     * @return 数据库表对应的主键信息
     */
    public List<TablePrimary> getPrimaryKey(JdbcTemplate jdbcTemplate) {
        Map<String, DataSourceTableInfo> dataSourceTableInfoMap = SpringUtil.getBean(new TypeReference<Map<String, DataSourceTableInfo>>() {
        });
        DataSourceTableInfo dataSourceTableInfo = dataSourceTableInfoMap.get(getSupports());
        Map<String, List<String>> tablePrimaryMap = dataSourceTableInfo.getTablePrimary(jdbcTemplate);
        return TABLE_X_INFOS.stream().map(tableXInfo -> {
            TablePrimary tablePrimary = new TablePrimary();
            tablePrimary.setTableName(tableXInfo.getTableName());
            List<String> primaryFieldNames = tableXInfo.getTableFieldXInfos()
                    .stream().filter(tableFieldXInfo -> {
                        Boolean primary = tableFieldXInfo.getPrimary();
                        if (primary && tableFieldXInfo.getNullable()) {
                            throw new IllegalArgumentException("The primary key field cannot be empty!");
                        }
                        return primary;
                    })
                    .map(TableFieldXInfo::getFieldName)
                    .collect(Collectors.toList());
            tablePrimary.setPrimaryIds(primaryFieldNames);
            return tablePrimary;
        }).filter(tablePrimary -> {
            String tableName = tablePrimary.getTableName();
            if (!tablePrimaryMap.containsKey(tableName)) {
                return Boolean.TRUE;
            }
            List<String> primaryIds = tablePrimary.getPrimaryIds();
            List<String> dataSourcePrimaryIds = tablePrimaryMap.get(tableName);
            ListChange<String> change = ListUtilX.getChange(primaryIds, dataSourcePrimaryIds);
            if (CollUtil.isEmpty(change.getNeedAdd()) && CollUtil.isEmpty(change.getNeedDel())) {
                return Boolean.FALSE;
            }
            return Boolean.TRUE;
        }).collect(Collectors.toList());
    }

    /**
     * 获取需要新增的表信息
     *
     * @return 新增表信息
     */
    public List<? extends TableXInfo> getAddTable() {
        List<String> tableNames = TABLE_INFOS.stream().map(TableInfo::getTableName)
                .collect(Collectors.toList());
        return TABLE_X_INFOS.stream().filter(item -> !tableNames.contains(item.getTableName()))
                .collect(Collectors.toList());
    }

    /**
     * 获取需要更新的表信息
     *
     * @return 更新表信息
     */
    public List<? extends TableUpdateInfo> getUpdateTable() {
        Map<String, String> tableCommentMap = TABLE_INFOS.stream()
                .collect(Collectors.toMap(TableInfo::getTableName, TableInfo::getTableComment));
        return TABLE_X_INFOS.stream().filter(item -> {
            String tableName = item.getTableName();
            if (tableCommentMap.containsKey(tableName)) {
                return !tableCommentMap.get(tableName).equals(item.getComment());
            } else {
                return false;
            }
        }).map(item -> {
            TableUpdateInfo tableUpdateInfo = new TableUpdateInfo();
            tableUpdateInfo.setTableName(item.getTableName());
            tableUpdateInfo.setTableComment(item.getComment());
            return tableUpdateInfo;
        }).collect(Collectors.toList());
    }

    /**
     * 获取需要删除的表名称
     *
     * @return 删除的表名称
     */
    public List<String> getDeleteTable() {
        List<String> tableXNames = TABLE_X_INFOS.stream().map(TableXInfo::getTableName)
                .collect(Collectors.toList());
        return TABLE_INFOS.stream().map(TableInfo::getTableName)
                .filter(item -> !tableXNames.contains(item))
                .collect(Collectors.toList());
    }

    /**
     * 获取需要新增的表字段信息
     *
     * @return 新增的表字段信息
     */
    public List<? extends TableFieldXInfo> getAddColumn() {
        Map<String, List<String>> tableColumnMap = new HashMap<>();
        TABLE_INFOS.stream().forEach(tableInfo -> {
            String tableName = tableInfo.getTableName();
            List<String> tableColumnList = tableColumnMap.getOrDefault(tableName, new ArrayList<>());
            List<String> tableColumn = tableInfo.getTableColumns().stream().map(TableColumn::getColumnName)
                    .collect(Collectors.toList());
            tableColumnList.addAll(tableColumn);
            tableColumnMap.put(tableName, tableColumnList);
        });
        return TABLE_X_INFOS.stream().flatMap(item -> item.getTableFieldXInfos().stream())
                .filter(item -> {
                    String tableName = item.getTableName();
                    if (!tableColumnMap.containsKey(tableName)) {
                        return false;
                    }
                    List<String> tableColumnList = tableColumnMap.get(tableName);
                    return !tableColumnList.contains(item.getFieldName());
                }).collect(Collectors.toList());
    }

    /**
     * 获取需要更新的表字段信息
     *
     * @return 更新的表字段信息
     */
    public List<? extends TableFieldXInfo> getUpdateColumn() {
        Map<String, TableFieldXInfo> tableColumnInfos = TABLE_INFOS.stream()
                .flatMap(tableInfo -> tableInfo.getTableColumns().stream())
                .map(tableColumn -> {
                    TableFieldXInfo tableFieldXInfo = new TableFieldXInfo();
                    tableFieldXInfo.setTableName(tableColumn.getTableName());
                    tableFieldXInfo.setFieldName(tableColumn.getColumnName());
                    tableFieldXInfo.setFieldType(tableColumn.getColumnType());
                    tableFieldXInfo.setComment(tableColumn.getColumnComment());
                    tableFieldXInfo.setNullable(tableColumn.getNullAble());
                    return tableFieldXInfo;
                }).collect(Collectors.toMap(item -> item.getTableName() + item.getFieldName(), r -> r));
        return TABLE_X_INFOS.stream().flatMap(tableXInfo -> tableXInfo.getTableFieldXInfos().stream())
                .filter(tableFieldXInfo -> {
                    String fieldKey = tableFieldXInfo.getTableName() + tableFieldXInfo.getFieldName();
                    if (!tableColumnInfos.containsKey(fieldKey)) {
                        return false;
                    }
                    TableFieldXInfo tableFieldInfo = tableColumnInfos.get(fieldKey);
                    if (!tableFieldXInfo.getFieldType().equalsIgnoreCase(tableFieldInfo.getFieldType())) {
                        return true;
                    }
                    if (!tableFieldXInfo.getComment().equals(tableFieldInfo.getComment())) {
                        return true;
                    }
                    return !tableFieldXInfo.getNullable().equals(tableFieldInfo.getNullable());
                }).collect(Collectors.toList());
    }

    /**
     * 获取需要删除的表字段信息
     *
     * @return 删除的表字段信息
     */
    public List<? extends TableFieldDel> getDeleteColumn() {
        Map<String, List<String>> tableColumnMap = new HashMap<>();
        TABLE_X_INFOS.stream().forEach(tableInfo -> {
            String tableName = tableInfo.getTableName();
            List<String> tableColumnList = tableColumnMap.getOrDefault(tableName, new ArrayList<>());
            List<String> tableColumn = tableInfo.getTableFieldXInfos().stream().map(TableFieldXInfo::getFieldName)
                    .collect(Collectors.toList());
            tableColumnList.addAll(tableColumn);
            tableColumnMap.put(tableName, tableColumnList);
        });
        return TABLE_INFOS.stream().flatMap(item -> item.getTableColumns().stream())
                .filter(item -> {
                    String tableName = item.getTableName();
                    if (tableColumnMap.containsKey(tableName)) {
                        return false;
                    }
                    List<String> tableColumnList = tableColumnMap.get(tableName);
                    return !tableColumnList.contains(item.getColumnName());
                }).map(item -> {
                    TableFieldDel tableFieldDel = new TableFieldDel();
                    tableFieldDel.setTableName(item.getTableName());
                    tableFieldDel.setFieldName(item.getColumnName());
                    return tableFieldDel;
                }).collect(Collectors.toList());
    }

}
